// -----------------------------------------------------------
// Color.java
// -----------------------------------------------------------

package toolib.util;

import java.awt.Color;

/**
 * The Color class provides several methods to convert 
 * colors of the RGB patter into PGraphic usable Integers 
 * for <a href="http://www.processing.org/">processing</a>.
 * 
 * @author Steffen Fiedler <a target="_blank" href="http://www.comkee.de">www.comkee.de</a>
 */
public class ColorUtil {
	
	private final static String checkRGB (String theRGB) {
		if (theRGB.length () == 6 && !theRGB.contains ("#")) {
			return theRGB;
		}else{
			if (theRGB.charAt (0) == '#') {
				theRGB = theRGB.substring (1, theRGB.length ());
			}
			if (theRGB.length () > 6) {
				theRGB = theRGB.substring (0, 6);
			}
			return theRGB;
		}
	}
	
	/**
	 * Creates a non transparent PGraphics processable grey 
	 * tone by a given float grey value.
	 * <p/>
	 * <code>int myColor = Color.grey (105);</code>
	 * @param theGrey Grey portion from 0 to 1
	 * @return Color value as Integer
	 */
	public final static int grey (float theGrey) {
		if (theGrey < 0) theGrey = 0;
		if (theGrey > 1) theGrey = 1;
		theGrey *= 255;
		return (int) Long.parseLong (String.format ("%02X%02X%02X%02X", 
													255, 
													(int) theGrey, 
													(int) theGrey, 
													(int) theGrey), 16);
	}
	
	/**
	 * Creates a PGraphics processable grey tone by 
	 * a given Integer grey value and a transparency.
	 * <p/>
	 * <code>int myColor = Color.grey (.3f, .77f);</code>
	 * 
	 * @param theGrey Grey portion from 0 to 1
	 * @param theAlpha Level of transparency from 0 to 1
	 * @return Color value as Integer
	 */
	public final static int grey (float theGrey, float theAlpha) {
		if (theGrey < 0)	theGrey = 0;
		if (theGrey > 1)	theGrey = 1;
		if (theAlpha < 0)	theAlpha = 0;
		if (theAlpha > 1)	theAlpha = 1;
		theGrey	*= 255;
		theAlpha *= 255;
		return (int) Long.parseLong (String.format ("%02X%02X%02X%02X", 
													(int) theAlpha, 
													(int) theGrey, 
													(int) theGrey, 
													(int) theGrey), 16);
	}
	
	/**
	 * Creates a non transparent PGrahics processable grey 
	 * tone by a given Integer gery value.
	 * <p/>
	 * <code>int myColor = Color.grey (75);</code>
	 * 
	 * @param theGrey Grey portion from 0 to 255
	 * @return Color value as Integer
	 */
	public final static int grey (int theGrey) {
		if (theGrey < 0)	theGrey = 0;
		if (theGrey > 255)	theGrey = 255;
		return (int) Long.parseLong (String.format ("%02X%02X%02X%02X", 
													255, 
													theGrey, 
													theGrey, 
													theGrey), 16);
	}
	
	/**
	 * Creates a PGraphics processable grey tone by 
	 * a given Integer grey value and a transparency.
	 * </p>
	 * <code>int myColor = Color.grey (255, 105);</code>
	 * 
	 * @param theGrey Grey portion from 0 to 255
	 * @param theAlpha Level of transparency from 0 to 255
	 * @return Color value as Integer
	 */
	public final static int grey (int theGrey, int theAlpha) {
		if (theGrey < 0)	theGrey 	= 0;
		if (theGrey > 255)	theGrey		= 255;
		if (theAlpha < 0)	theAlpha	= 0;
		if (theAlpha > 255)	theAlpha	= 255;
		return (int) Long.parseLong (String.format ("%02X%02X%02X%02X", 
													theAlpha, 
													theGrey, 
													theGrey, 
													theGrey), 16);
	}
	
	public final static int getHueByStake (float theStake) {
		return Color.HSBtoRGB (theStake, 1f, 1f);
	}
	
	public final static int getHueByStake (float theStake, int theAlpha) {
		return setAlpha (Color.HSBtoRGB (theStake, 1f, 1f), theAlpha);
	}
	
	public final static int getHueByStake (float theStake, float theAlpha) {
		return getHueByStake (theStake, (int) (255 * theAlpha));
	}
	
	public final static int rgb (int theRed, int theGreen, int theBlue) {
		return rgb (theRed, theGreen, theBlue, 255);
	}
	
	/**
	 * Creates a PGrahics processable color value as 
	 * Integer from the given RGB and transparency 
	 * parameters.
	 * <p/>
	 * <code>int myColor = Color.rgb (255, 0, 102, 255);</code>
	 *   
	 * @param theR Red unit from 0 to 255
	 * @param theG Green unit from 0 to 255
	 * @param theB Blue unit from 0 to 255
	 * @param theAlpha Transparency value from 0 to 255
	 * @return Color value as Integer
	 */
	public final static int rgb (int theRed, int theGreen, int theBlue, int theAlpha) {
		return theAlpha << 24 | ((theRed << 16) & 0x00ff0000) | ((theGreen << 8) & 0x0000ff00) | (theBlue & 0x000000ff);
	}
	
	public final static int rgb (int theRed, int theGreen, int theBlue, float theAlpha) {
		return rgb (theRed, theGreen, theBlue, (int) (theAlpha * 255));
	}
	
	/**
	 * Creates a PGrahics processable color value as 
	 * Integer from the given RGB and transparency 
	 * parameters. Value range is checked before conversion.
	 * <p/>
	 * <code>int myColor = Color.rgb (1f, 0f, .4f, 1f);</code>
	 * 
	 * @param theR Red unit from 0 to 1
	 * @param theG Green unit from 0 to 1
	 * @param theB Blue unit from 0 to 1
	 * @param theAlpha Transparency value from 0 to 1
	 * @return Color value as Integer
	 */
	public final static int rgb (float theRed, float theGreen, float theBlue) {
		return rgb (theRed * 255, theGreen * 255, theBlue * 255);
	}
	
	/**
	 * Creates a PGrahics processable color value as 
	 * Integer from the given RGB and transparency 
	 * parameters. Value range is checked before conversion.
	 * <p/>
	 * <code>int myColor = Color.rgb (1f, 0f, .4f, 1f);</code>
	 * 
	 * @param theR Red unit from 0 to 1
	 * @param theG Green unit from 0 to 1
	 * @param theB Blue unit from 0 to 1
	 * @param theAlpha Transparency value from 0 to 1
	 * @return Color value as Integer
	 */
	public final static int rgb (float theRed, float theGreen, float theBlue, float theAlpha) {
		return rgb (theRed * 255, theGreen * 255, theBlue * 255, theAlpha * 255);
	}
	
	/**
	 * Creates a non transparent PGraphics processable color 
	 * value as Integer from the given RGB hex String.
	 * <p/>
	 * <code>int myColor = Color.rgb ("ff0066");</code>
	 * @param theRGB Color value as hex String without leading "#". 
	 * Formated like <code>RRGGBB</code>.
	 * @return
	 */
	public final static int rgb (String theRGB) {
		return (int) Long.parseLong ("FF" + checkRGB (theRGB), 16);
	}
	
	/**
	 * Creates a PGraphic processable color value as Integer 
	 * from the given RGB hex String and the transparency 
	 * parameter.
	 * </p>
	 * <code>int myColor = Color.rgb ("ff0066", .1f);</code>
	 * 
	 * @param theRGB Color value as hex String without leading "#". 
	 * Formated like <code>RRGGBB</code>.
	 * @param theAlpha Transparency value from 0 to 1. Choose 
	 * 0 for completely transparent and 1 for full saturation.
	 * @return Color value as Integer
	 */
	public final static int rgb (String theRGB, float theAlpha) {
		if (theAlpha < 0) theAlpha = 0;
		if (theAlpha > 1) theAlpha = 1;
		return (int) Long.parseLong (Integer.toHexString ((int) (theAlpha * 255)) + checkRGB (theRGB), 16);
	}
	
	/**
	 * Creates a PGraphic processable color value as Integer 
	 * from the given RGB hex String and the transparency 
	 * parameter.
	 * </p>
	 * <code>int myColor = Color.rgb ("ff0066", 255);</code>
	 * 
	 * @param theRGB Color value as hex String without leading "#". 
	 * Formated like <code>RRGGBB</code>.
	 * @param theAlpha Transparency value from 0 to 255. Choose 
	 * 0 for completely transparent and 255 for full saturation
	 * @return Color value as Integer
	 */
	public final static int rgb (String theRGB, int theAlpha) {
		if (theAlpha < 0) 	theAlpha = 0;
		if (theAlpha > 255) theAlpha = 255;
		return (int) Long.parseLong (Integer.toHexString (theAlpha) + checkRGB (theRGB), 16);
	}
	
	/**
	 * Interpolates a color between two given color codes.
	 * 
	 * @param theColor1 Start color.
	 * @param theColor2 End color.
	 * @param thePercentage Percentage amount between both colors.
	 * @return
	 */
	public final static int lerpRGB (int theColor1, int theColor2, float thePercentage) {
		float a1 = ((theColor1 >> 24) & 0xff);
		float r1 = (theColor1 >> 16) & 0xff;
		float g1 = (theColor1 >> 8) & 0xff;
		float b1 = theColor1 & 0xff;
		
		float a2 = (theColor2 >> 24) & 0xff;
		float r2 = (theColor2 >> 16) & 0xff;
		float g2 = (theColor2 >> 8) & 0xff;
		float b2 = theColor2 & 0xff;
		
		return ((int) (a1 + (a2 - a1) * thePercentage) << 24 | 
				(int) (r1 + (r2 - r1) * thePercentage) << 16 |
				(int) (g1 + (g2 - g1) * thePercentage) << 8 |
				(int) (b1 + (b2 - b1) * thePercentage)
				);
	}
	
	public final static int lerpRGB (int theColor1, int theColor2, float thePercentage, float theAlpha) {
		float r1 = (theColor1 >> 16) & 0xff;
		float g1 = (theColor1 >> 8) & 0xff;
		float b1 = theColor1 & 0xff;
		
		float r2 = (theColor2 >> 16) & 0xff;
		float g2 = (theColor2 >> 8) & 0xff;
		float b2 = theColor2 & 0xff;
		
		return ((int) (255 * theAlpha) << 24 | 
				(int) (r1 + (r2 - r1) * thePercentage) << 16 | 
				(int) (g1 + (g2 - g1) * thePercentage) << 8 | 
				(int) (b1 + (b2 - b1) * thePercentage) 
				);
	}
	
	/**
	 * Interpolates a color between two given color codes.
	 * 
	 * @param theColor1 Start color.
	 * @param theColor2 End color.
	 * @param thePercentage Percentage amount between both colors.
	 * @return
	 */
	public final static int lerpRGB (String theColor1, String theColor2, float thePercentage) {
		return lerpRGB (rgb (theColor1), rgb (theColor2), thePercentage);
	}
	
	public final static int lerpRGB (String theColor1, String theColor2, float thePercentage, float theAlpha) {
		return lerpRGB (rgb (theColor1), rgb (theColor2), thePercentage, theAlpha);
	}
	
	/**
	 * Get the alpha (transparency) component of a given color.
	 * 
	 * @param theRGB The color code.
	 * @return The alpha component of the color, between 0-255.
	 */
	public final static int getAlpha (int theRGB) {
		return (theRGB >> 24) & 0xff;
	}
	
	/**
	 * Get the blue component of a given color.
	 * 
	 * @param theRGB The color code.
	 * @return The blue component of the color, between 0-255.
	 */
	public final static int getBlue (int theRGB) {
		return theRGB & 0xff;
	}
	
	public final static float getBrightness (int theRed, int theBlue, int theGreen) {
		return (theRed + theGreen + theBlue) / 765;
	}
	
	/**
	 * Get the green component of a given color.
	 * 
	 * @param theRGB The color code.
	 * @return The green component of the color, between 0-255.
	 */
	public final static int getGreen (int theRGB) {
		return (theRGB >> 8) & 0xff;
	}
	
	/**
	 * Get the red component of a given color.
	 * 
	 * @param theRGB The color code.
	 * @return The red component of the color, between 0-255.
	 */
	public final static int getRed (int theRGB) {
		return (theRGB >> 16) & 0xff;
	}
	
	public final static int setAlpha (int theRGB, int theAlpha) {
		return (theRGB & 0xffffff) | (theAlpha << 24);
	}
	
	public final static int setAlpha (int theRGB, float theAlpha) {
		return setAlpha (theRGB, (int) (255 * theAlpha));
	}
	
	public final static int setBlue (int theRGB, int theBlue) {
		return (theRGB & 0xffffff00) | theBlue;
	}
	
	public final static int setBlue (int theRGB, float theBlue) {
		return setBlue (theRGB, (int) (255 * theBlue));
	}
	
	public final static int setGreen (int theRGB, int theGreen) {
		return (theRGB & 0xffff00ff) | (theGreen << 8);
	}
	
	public final static int setGreen (int theRGB, float theGreen) {
		return setGreen (theRGB, (int) (255 * theGreen));
	}
	
	public final static int setRed (int theRGB, int theRed) {
		return (theRGB & 0xff00ffff) | (theRed << 16);
	}
	
	public final static int setRed (int theRGB, float theRed) {
		return setRed (theRGB, (int) (255 * theRed));
	}
}